#include"DroneControler.h"

#include"Info.h"
#include"BuildHelper.h"
#include"ProductionTask.h"

DroneControler::DroneControler(Unit* drone)
	:UnitControlerBaseClass(drone , 0),
	_IamDead(false),
	_state(IdleDrone),
	_notMiningFrameCount(0),
	_notMiningFrameMax(23),
	_inThisBase(NULL),
	_distanceToTarget(0.0),
	_productionTask(NULL)
{
}
void DroneControler::OnFrame()
{
	if(_state == IdleDrone)
	{
		IdleFunction();
	}
	else if(_state == Mining)
	{
		MiningFunction();
	}
	else if(_state == Gasing)
	{
		GasingFunction();
	}
	else if(_state == PlaceBuilding)
	{
		PlaceBuildingFunction();
	}

	Draw();
}
bool DroneControler::ShouldRemove()
{
	return !_me->exists() || _me->getType() != UnitTypes::Zerg_Drone;
}
void DroneControler::Build(UnitType unitType , int baseIndex)
{
	TilePosition buildTile(BuildHelper::Instance().GetABuildTile(unitType , baseIndex));
	if(buildTile.isValid())
	{
		_buildTask.Set(buildTile , baseIndex , unitType);
		_distanceToTarget = Info::Instance().GetBaseInfo(_me->getTilePosition())->GetDistanceToBase(Info::Instance().GetBaseInfo(baseIndex)) + 150.0;
	}
}
void DroneControler::Build(ProductionTask& productionTask)
{
	TilePosition buildTile(BuildHelper::Instance().GetABuildTile(productionTask.GetBuildType() , productionTask.GetBaseIndex()));
	if(buildTile.isValid())
	{
		_buildTask.Set(buildTile , productionTask.GetBaseIndex() , productionTask.GetBuildType());
		_distanceToTarget = Info::Instance().GetBaseInfo(_me->getTilePosition())->GetDistanceToBase(Info::Instance().GetBaseInfo(productionTask.GetBaseIndex())) + 150.0;
		productionTask.SetState(ProductionTask::Asigned);
		_productionTask = &productionTask;
	}
}
void DroneControler::HarvestGas(Unit* geyser)
{
	_state = Gasing;
	_me->rightClick(geyser);
}
//--
void DroneControler::IdleFunction()
{
	_inThisBase = Info::Instance().AssignMeToMineral(_me);
	if(_inThisBase != NULL)
	{
		_state = Mining;
	}
}
void DroneControler::MiningFunction()
{
	if(_buildTask.NoTask())
	{
		const Order& currentOrder((_me->getOrder()));
		if(_inThisBase->HatcheryCantReturnResource())
		{
			_notMiningFrameCount = 0;
			LeaveBase();
			_state = IdleDrone;
		}
		else if(IsMiningOrder(currentOrder))
		{
			_notMiningFrameCount = 0;
		}
		else
		{
			++_notMiningFrameCount;
			if(_notMiningFrameCount > _notMiningFrameMax)
			{
				_notMiningFrameCount = 0;
				LeaveBase();
				_state = IdleDrone;
			}
		}
	}
	else
	{
		if(ShouldStartBuild())
		{
			LeaveBase();
			_state = PlaceBuilding;
			_productionTask->SetState(ProductionTask::Depart);
		}
	}
}
void DroneControler::GasingFunction()
{
	const Order& currentOrder((_me->getOrder()));
	if(IsGasingOrder(currentOrder))
	{
		_notMiningFrameCount = 0;
	}
	else
	{
		++_notMiningFrameCount;
		if(_notMiningFrameCount > 200)
		{
			_notMiningFrameCount = 0;
			LeaveBase();
			_state = IdleDrone;
		}
	}
}
void DroneControler::PlaceBuildingFunction()
{
	if(!_me->exists())
	{
		if(_buildTask.GetBuildType() == UnitTypes::Zerg_Extractor)
		{
			if(_buildTask.GetGeySer()->getType() != UnitTypes::Zerg_Extractor)
			{
				_productionTask->SetState(ProductionTask::Dead);
			}
			else
			{
				_me = _buildTask.GetGeySer();
				_productionTask->SetState(ProductionTask::Morphing);
			}
		}
		else
		{
			_productionTask->SetState(ProductionTask::Dead);
		}		
	}
	else
	{
		if(_me->getType() != UnitTypes::Zerg_Drone)
		{
			_productionTask->SetState(ProductionTask::Morphing);
		}
		else 
		{
			const TilePosition& buildTile(_buildTask.GetBuildTile());
			if(_me->getPosition().getDistance(_buildTask.GetBuildPosition()) < 150.0)
			{
				if(BuildHelper::Instance().IsBuildTileBlocked(_buildTask.GetBuildType() , _buildTask.GetBuildTile() , _me))
				{
					Build(_buildTask.GetBuildType() , _buildTask.GetBaseIndex());
				}
				else
				{
					_me->build(buildTile , _buildTask.GetBuildType());
				}
			}
			else
			{
				_me->move(_buildTask.GetBuildPosition());
			}
		}
	}
}
void DroneControler::LeaveBase()
{
	if(_inThisBase != NULL)
	{
		_inThisBase->IamLeaving(_me);
		_inThisBase = NULL;
	}
}
bool DroneControler::IsMiningOrder(const Order& order)
{
	return order == Orders::MoveToMinerals
		|| order == Orders::MiningMinerals
		|| order == Orders::ReturnMinerals;
}
bool DroneControler::IsGasingOrder(const Order& order)
{
	return order == Orders::MoveToGas
		|| order == Orders::WaitForGas
		|| order == Orders::HarvestGas
		|| order == Orders::ReturnGas;
}
bool DroneControler::ShouldStartBuild() const
{
	const double travelTime = _distanceToTarget / _me->getType().topSpeed();
	const double mineralPrice = (double)_buildTask.GetBuildType().mineralPrice();
	const double gasPrice = (double)_buildTask.GetBuildType().gasPrice();
	//--
	if(mineralPrice > 0)
	{
		if(travelTime < (mineralPrice - (double)Broodwar->self()->minerals()) / Info::Instance().MineralRateWithoutOneWorker())
		{
			return false;
		}
	}

	if(gasPrice > 0)
	{
		if(travelTime < (gasPrice - (double)Broodwar->self()->gas()) / Info::Instance().GasRate())
		{
			return false;
		}
	}

	return true;
}
void DroneControler::Draw()
{
	const char* stateNames[] = {"IdleDrone" , "Mining" , "Gasing" , "PlaceBuilding"};
	Broodwar->drawTextMap(_me->getLeft() , _me->getTop() - 21 , "Drone: %s" , stateNames[_state]);
}